package physics;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.TextField;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JLabel;

/**
 * Display animations.
 * @author Krasimir Baylov(61080), Stanislav Petrov(61055)
 * @version 1.0
 */
public class AnimationPanel extends javax.swing.JPanel {

    private final int TOOLTIP_OFFSET = 40;
    /**
     * The target object that will be drawn on the panel
     */
    private Target target;
    /**
     * Graphics object for the panel
     */
    public Graphics myGraphics;
    /**
     * Indicates wheter tool tip should be redrawn or not.
     */
    private boolean drawnToolTip;
    /**
     * Indicates whether panel should be repainted for tool tip to be removed.
     */
    private boolean toBeRepainted;
    /**
     * Horizontal distance between gun and target.
     */
    private double targetHorizontalDistance;
    /**
     * Vertical distance between gun and target.
     */
    private double targetVerticalDistance;

    /**
     * Creates new Animation panel.
     */
    public AnimationPanel() {
        initComponents();
        target = new Target();
        setOpaque(true);
        setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
        toBeRepainted = true;
    }

    /**
     * Set the angle in the gun panel.
     * @param angleValue Angle value to be set.
     */
    public void setAngle(double angleValue) {
        gunPnl.setAngle(angleValue);
    }

    /**
     * Redraws target when panel is resized.
     * @param g
     */
    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        target.reDrawTarget(g);
    }

    /**
     * Draws target with random coordinates.
     */
    public void drawTarget() {
        myGraphics = this.getGraphics();
        target.drawRandomCoordinates(myGraphics, getWidth(), getHeight());
        repaint();
    }

    /**
     * Coordinates of the top of the gun.
     * @return Point coordinates of the top of the gun.
     */
    public Point getGunCoorinates() {
        return gunPnl.getTopCoordinates();
    }

    /**
     * Target's object reference getter.
     * @return Target reference.
     */
    public Target getTarget() {
        return target;
    }

    /**
     * Target upper left corner point getter.
     * @return the point of the target
     */
    public Point getTargetPoint() {
        return target.getPoint();
    }

    /**
     * Target center point getter. Used in moving ball class for checking
     * whether target is hitted by the ball.
     * @return Target center point.
     */
    public Point getTargetCenterPoint() {
        return target.getCenterPoint();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        gunPnl = new physics.GunPanel();

        setPreferredSize(new java.awt.Dimension(550, 500));
        addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                formMouseMoved(evt);
            }
        });

        javax.swing.GroupLayout gunPnlLayout = new javax.swing.GroupLayout(gunPnl);
        gunPnl.setLayout(gunPnlLayout);
        gunPnlLayout.setHorizontalGroup(
            gunPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 200, Short.MAX_VALUE)
        );
        gunPnlLayout.setVerticalGroup(
            gunPnlLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 200, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(gunPnl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(350, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(300, Short.MAX_VALUE)
                .addComponent(gunPnl, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void formMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseMoved
        drawToolTip(evt.getPoint());
    }//GEN-LAST:event_formMouseMoved

    /**
     * Checks wheter mouse is over the target and draws tool tip associated with
     * target.
     * @param mousePoint Stores mouse coordinates.
     */
    private void drawToolTip(Point mousePoint) {
        Point targetCenterPoint = target.getCenterPoint();
        if (isInsideTarget(mousePoint)) {
            if (!drawnToolTip) {
                Graphics2D g = (Graphics2D) this.getGraphics();
                Font font = new Font("Monospaced", Font.PLAIN, 15);
                FontRenderContext frc = g.getFontRenderContext();
                TextLayout layout = new TextLayout(String.format("distance: %.2f", calculateDistanceGunTarget()),
                        font, frc);
                Rectangle2D bounds = layout.getBounds();
                bounds.setRect(bounds.getX() + targetCenterPoint.x + TOOLTIP_OFFSET,
                        bounds.getY() + targetCenterPoint.y - 3,
                        bounds.getWidth(), bounds.getHeight() + 6);
                /*
                 * Second condition: Indicates if too tip is longer than free
                 * space in panel.
                 */
                double limitWidth = getWidth() - bounds.getX();
                if (limitWidth >= bounds.getWidth()) {
                    layout.draw(g, (float) targetCenterPoint.x + TOOLTIP_OFFSET,
                            (float) targetCenterPoint.y);
                    g.draw(bounds);
                } else {
                    layout.draw(g, (float) targetCenterPoint.x - 5 * TOOLTIP_OFFSET, (float) targetCenterPoint.y);
                    bounds = layout.getBounds();
                    bounds.setRect(bounds.getX() + targetCenterPoint.x - 5 * TOOLTIP_OFFSET,
                            bounds.getY() + targetCenterPoint.y - 3,
                            bounds.getWidth(),
                            bounds.getHeight() + 6);
                    g.draw(bounds);
                }
                drawnToolTip = true;
                toBeRepainted = true;
            }
        } else {
            if (toBeRepainted) {
                repaint();
                drawnToolTip = false;
                toBeRepainted = false;
            }
        }
    }

    /**
     * Checks wheter mouse cursor is over the target.
     * @param mousePoint Mouse cursor coordinates.
     * @return True - if mouse is inside target, false - otherwise.
     */
    public boolean isInsideTarget(Point mousePoint) {
        Point targetCenterPoint = target.getCenterPoint();
        if (mousePoint.x >= targetCenterPoint.x - Target.TARGET_SIZE / 2 &&
                mousePoint.x <= targetCenterPoint.x + Target.TARGET_SIZE / 2 &&
                mousePoint.y >= targetCenterPoint.y - Target.TARGET_SIZE / 2 &&
                mousePoint.y <= targetCenterPoint.y + Target.TARGET_SIZE / 2) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Calculates distance between top of the gun and target center.
     * @return Distance value.
     */
    public double calculateDistanceGunTarget() {
        Point targetCenter = target.getCenterPoint();
        if (targetCenter.x == -75) {
            targetHorizontalDistance = 0;
            targetVerticalDistance = 0;
        } else {
            Point gunPoint = gunPnl.getTopCoordinates();
            targetHorizontalDistance = Math.abs(targetCenter.x - gunPoint.x);
            targetVerticalDistance = Math.abs(getHeight() - targetCenter.y - gunPoint.y);

        }
        double a = targetHorizontalDistance * targetHorizontalDistance;
        double b = targetVerticalDistance * targetVerticalDistance;
        return Math.sqrt(a + b) / 10;
    }

    /**
     * Horizontal target's distance from top of the gun getter.
     * @return Horizontal distance value representation.
     */
    public String getTargetHorizontalDistance() {
        return String.format("%.0f", targetHorizontalDistance);
    }

    /**
     * Vertical target's distance from top of the gun getter.
     * @return Vertical distance value representation.
     */
    public String getTargetVerticalDistance() {
        return String.format("%.0f", targetVerticalDistance);
    }

    /**
     * Gun panel which visualizes the gun.
     */
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private physics.GunPanel gunPnl;
    // End of variables declaration//GEN-END:variables
}

